package boccuz.rnn.state;

import java.util.List;

import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.UnicodeFont;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;

import boccuz.rnn.Asset;
import boccuz.rnn.Constants;
import boccuz.rnn.Direction;
import boccuz.rnn.Entity;
import boccuz.rnn.GameData;
import boccuz.rnn.Settings;
import boccuz.rnn.State;
import boccuz.rnn.Vector2I;
import boccuz.rnn.Viewport;
import boccuz.rnn.enemy.EnemyFactory;
import boccuz.rnn.helper.FontHelper;
import boccuz.rnn.helper.TimeHelper;

public class PlayState extends BasicGameState {
	private static final int PLAYER_WIDTH = 32;
	private static final int PLAYER_HEIGHT = 64;

	private static final int PLAYER_CENTER_X = Settings.WIDTH / 2
			- PLAYER_WIDTH / 2;
	private static final int PLAYER_CENTER_Y = Settings.HEIGHT / 2
			- PLAYER_HEIGHT / 2;

	private static final int TIMER_MASK_HEIGHT = 92;

	private Entity player;
	private Viewport viewport;
	private UnicodeFont font;

	private float scoreFader = 1F;
	private float levelFader = 1F;
	private float timerFader = 1F;
	private long gameTime;
	private TimeHelper timerTimeHelper;
	private long timerTime;
	private EnemyFactory enemyFactory;
	private long spawnTimer;
	

	@Override
	public void init(GameContainer gc, StateBasedGame sbg)
			throws SlickException {
		Asset.loadImage(Asset.IMG_PLAY_HUD_TIMER, 0.25F);
		Asset.loadImage(Asset.IMG_PLAY_HUD_TIMER_WHEEL, 0.25F);
		player = new Entity(Asset.IMG_PLAY_PLAYER, 32, 64);
		player.pos = new Vector2I(PLAYER_CENTER_X, PLAYER_CENTER_Y);
		viewport = new Viewport(Constants.MAP_WIDTH, Constants.MAP_HEIGHT);

		font = FontHelper.get(Asset.FNT_GOCHI_HAND, 45, false, false,
				Constants.COLOR_2);

		GameData.currentLevel = 1;

		timerTimeHelper = new TimeHelper();
		timerTimeHelper.initTimer();
		
		gameTime = Constants.GAME_TIME;
		enemyFactory = new EnemyFactory();
	}

	@Override
	public void render(GameContainer gc, StateBasedGame sbg, Graphics g)
			throws SlickException {
		g.setFont(font);

		// Background
		viewport.drawBackground(Asset.getImage(Asset.IMG_PLAY_BACKGROUND_1), g);

		// Player
		viewport.draw(player, g);

		// Draw the enemies
		List<Entity> entities = enemyFactory.getEnemies();
		for(Entity e : entities){
			viewport.draw(e, g);
		}
		
		// -- HUD --
		// Score
		Asset.getImage(Asset.IMG_PLAY_HUD_SCORE).draw(15, 15);
		// The score is rotated on the left
		g.rotate(0, 0, -Constants.TEXT_ANGLE.floatValue());
		g.drawString(String.valueOf(GameData.score), 55, 35);
		g.rotate(0, 0, Constants.TEXT_ANGLE.floatValue());
		// TODO fade the score

		// Level
		Asset.getImage(Asset.IMG_PLAY_HUD_LEVEL).draw(580, 15);
		g.rotate(0, 0, Constants.TEXT_ANGLE.floatValue());
		g.drawString("Niv. " + String.valueOf(GameData.currentLevel), 620, -55);
		g.rotate(0, 0, -Constants.TEXT_ANGLE.floatValue());
		// TODO fade the level

		// Timer
		Asset.getImage(Asset.IMG_PLAY_HUD_TIMER).draw(15, 490);

		// Clipping power!
		g.setClip(24, 490, 55, TIMER_MASK_HEIGHT);
		Asset.getImage(Asset.IMG_PLAY_HUD_TIMER_WHEEL).draw(-167F, 115F);
		g.clearClip();
	}

	@Override
	public void update(GameContainer gc, StateBasedGame sbg, int t)
			throws SlickException {
		GameData.score++;

		int speed = 5;
		int x = 0;
		int y = 0;
		Input input = gc.getInput();
		if (input.isKeyDown(Input.KEY_LEFT) || input.isKeyDown(Input.KEY_Q)) {
			// Move left
			x -= speed;
		} else if (input.isKeyDown(Input.KEY_RIGHT)
				|| input.isKeyDown(Input.KEY_D)) {
			// Move Right
			x += speed;
		}

		if (input.isKeyDown(Input.KEY_UP) || input.isKeyDown(Input.KEY_Z)) {
			// Move up
			y -= speed;
		} else if (input.isKeyDown(Input.KEY_DOWN)
				|| input.isKeyDown(Input.KEY_S)) {
			// Move down
			y += speed;
		}

		// Move
		if (x != 0 || y != 0) {
			player.pos.x += x;
			player.pos.y += y;
			viewport.move(-x, -y);
			player.setMoving(true);

			// Move the background only if the player is not near a border
			if (player.pos.x <= PLAYER_CENTER_X) {
				viewport.viewportPos.x = 0;
			} else if (player.pos.x >= Constants.MAP_WIDTH - PLAYER_CENTER_X
					- PLAYER_WIDTH) {
				viewport.viewportPos.x = -Constants.MAP_WIDTH + Settings.WIDTH;
			}

			if (player.pos.y <= PLAYER_CENTER_Y) {
				viewport.viewportPos.y = 0;
			} else if (player.pos.y >= Constants.MAP_HEIGHT - PLAYER_CENTER_Y
					- PLAYER_HEIGHT) {
				viewport.viewportPos.y = -Constants.MAP_HEIGHT + Settings.HEIGHT;
			}

			// Prevents the player from going outside!
			if (player.pos.x < 0) {
				player.pos.x = 0;
			} else if (player.pos.x >= Constants.MAP_WIDTH - PLAYER_WIDTH) {
				player.pos.x = Constants.MAP_WIDTH - PLAYER_WIDTH;
			}

			if (player.pos.y < 0) {
				player.pos.y = 0;
			} else if (player.pos.y >= Constants.MAP_HEIGHT - PLAYER_HEIGHT) {
				player.pos.y = Constants.MAP_HEIGHT - PLAYER_HEIGHT;
			}

		} else {
			player.setMoving(false);
		}
		// Direction
		if ((x < 0 && y > 0) || (x < 0 && y == 0)) {
			// Left
			player.setCurrentDirection(Direction.LEFT);
		} else if ((x > 0 && y > 0) || (x == 0 && y > 0)) {
			// Down
			player.setCurrentDirection(Direction.DOWN);
		} else if ((x > 0 && y < 0) || (x > 0 && y == 0)) {
			// Right
			player.setCurrentDirection(Direction.RIGHT);
		} else if ((x < 0 && y < 0) || (x == 0 && y < 0)) {
			// Up
			player.setCurrentDirection(Direction.UP);
		}

		// HUD Awesomeness! :D
		doAwesomeHudEffects();

		// Timer rotation
		long elapsedTime = timerTimeHelper.getElapsedTime();
		timerTime += elapsedTime;
		gameTime -= elapsedTime;
		spawnTimer += elapsedTime;
		if (timerTime >= 1000) {
			// Rotate the timer to show that 1 second passed
			timerTime = 0;
			Asset.getImage(Asset.IMG_PLAY_HUD_TIMER_WHEEL).rotate(
					-Constants.TIMER_ANGLE);
		}
		
		if(gameTime <= 0){
			// The play time is over -> Game Over! :(
			sbg.enterState(State.GAME_OVER.ordinal());
		}
		
		if(spawnTimer > Constants.SPAWN_TIME){
			// Spawn enemies
			spawnTimer = 0;
			enemyFactory.createEnemy();
		}
		
		// 
		enemyFactory.update();
	}

	private void doAwesomeHudEffects() throws SlickException {
		// Score HUD
		if (player.pos.x < 200 && player.pos.y < 80) {
			if (scoreFader > 0.2F) {
				scoreFader -= 0.05F;

			}
		} else {
			if (scoreFader < 1F) {
				scoreFader += 0.05F;
			}
		}
		Asset.getImage(Asset.IMG_PLAY_HUD_SCORE).setAlpha(scoreFader);
		// TODO Handle the score text alpha value

		// Level HUD
		if (player.pos.x > Constants.MAP_WIDTH - 250 && player.pos.y < 80) {
			if (levelFader > 0.2F) {
				levelFader -= 0.05F;
			}
		} else {
			if (levelFader < 1F) {
				levelFader += 0.05F;
			}
		}
		Asset.getImage(Asset.IMG_PLAY_HUD_LEVEL).setAlpha(levelFader);
		// TODO Handle the level text alpha value

		// Timer HUD
		if (player.pos.x < 80 && player.pos.y > Constants.MAP_HEIGHT - 150) {
			if (timerFader > 0.2F) {
				timerFader -= 0.05F;
			}
		} else {
			if (timerFader < 1F) {
				timerFader += 0.05F;
			}
		}
		Asset.getImage(Asset.IMG_PLAY_HUD_TIMER).setAlpha(timerFader);
		Asset.getImage(Asset.IMG_PLAY_HUD_TIMER_WHEEL).setAlpha(timerFader);
		// TODO Handle the timer display alpha value
	}

	@Override
	public int getID() {
		return State.PLAY.ordinal();
	}

}
